home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
midi
/
gfft.lha
/
gfft-2.03
/
source
/
gfft-2.03-source.lha
/
format.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-02
|
15KB
|
574 lines
/***************************************************************************
* Copyright (C) 1994 Charles P. Peterson *
* 4007 Enchanted Sun, San Antonio, Texas 78244-1254 *
* Email: Charles_P_Peterson@fcircus.sat.tx.us *
* *
* This is free software with NO WARRANTY. *
* See gfft.c, or run program itself, for details. *
* Support is available for a fee. *
***************************************************************************
*
* Program: gfft--General FFT analysis
* File: format.c
* Purpose: parse formatted files
* Author: Charles Peterson (CPP)
* History: 18-October-1993 CPP; Created.
* Comment: Thanks to Guido van Rossum for SOX and David Champion
* for OmniPlay, from which much was learned.
* Thanks to Malcolm Slaney and Ken Turkowski for
* ConvertFromIeeeExtended, from which much was learned.
* However, this is an original implementation, containing
* no previously copyrighted code.
*/
#include <math.h>
#include <stdio.h>
#include "gfft.h"
#include "settings.h"
#include "format.h"
#define NO_ERROR FALSE
#define CORRUPT TRUE
#define UNAVAIL_COMPRESSION 2
static unsigned long offset = 0; /* Running offset pointer used here */
/*
* Static function declarations
*/
static void read_form_format (void); /* Includes 8SVX, AIFF, AIFC types */
static void read_8svx_format (long form_cksize);
static int read_vhdr (ULONG form_cksize, struct ChunkHeader chunk_h);
static void read_aiff_format (long form_cksize);
static int read_comm_aiff (ULONG form_cksize, struct ChunkHeader chunk_h);
static void read_aifc_format (long form_cksize);
static int read_comm_aifc (ULONG form_cksize, struct ChunkHeader chunk_h);
static double double_from_extended (UBYTE *extended);
static void read_avr_format (void);
void reset_format (void)
{
/*
* Reset Global Format Info
*/
FileFormat = UNFORMATTED;
FileFormatOK = FALSE;
FileRate = AUTO_RATE;
FileDataOffset = 0;
FileFrames = 0;
FileVolume = 1.0L;
FileOctaves = 1;
FileChannels = 1;
FileOneShotHiFrames = 0;
FileRepeatHiFrames = 0;
}
void read_format (void)
{
ID format_id;
int format = UNFORMATTED;
reset_format();
if (fread (&format_id, sizeof format_id, 1, ReadPtr))
{
offset = sizeof format_id; /* This is where offset count begins */
switch (format_id)
{
case ID_FORM: /* IFF 8SVX, AIFF, and AIFC */
format = ID_FORM; /* Clarified later */
break;
case ID_RIFF:
format = ID_RIFF;
break;
case ID_VOCH:
format = ID_VOCH;
break;
case ID_AVR:
format = ID_AVR;
break;
}
}
if (format != UNFORMATTED)
{
if (IgnoreFormat)
{
error_message (FILE_FORMAT_IGNORED);
return;
}
Rate = AUTO_RATE; /* override must be forced afterwards */
}
FileFormat = format;
switch (format)
{
case ID_FORM:
read_form_format ();
break;
case ID_AVR:
read_avr_format ();
break;
case UNFORMATTED:
break;
default:
error_message (UNSUPPORTED_FORMAT);
FileFormatOK = FALSE;
}
}
static void read_form_format (void) /* Includes 8SVX, AIFF, AIFC types */
{
ULONG form_cksize;
ID form_type;
if (fread (&form_cksize, sizeof form_cksize, 1, ReadPtr) &&
fread (&form_type, sizeof form_type, 1, ReadPtr))
{
offset += sizeof form_cksize + sizeof form_type;
switch (form_type)
{
case ID_8SVX:
FileFormat = ID_8SVX;
read_8svx_format (form_cksize);
break;
case ID_AIFF:
FileFormat = ID_AIFF;
read_aiff_format (form_cksize);
break;
case ID_AIFC:
FileFormat = ID_AIFC;
read_aifc_format (form_cksize);
break;
default:
error_message (UNSUPPORTED_FORMAT);
break;
}
}
else
{
error_message (CORRUPT_IFF); /* Missing cksize and/or type! */
}
}
static void read_8svx_format (long form_cksize)
/*
* Chunks are allowed to be in any order.
* But, a fast and lazy approach is taken to validation:
* Chunks looked for: VHDR and BODY
* (Once those two have been found, and VHDR read, I exit.)
* BODY chunk isn't read (so premature file end must be detected later)
* BODY chunk is fseek'd over only if VHDR hasn't been found yet.
* form_cksize isn't actually checked
*/
{
int error = NO_ERROR;
struct ChunkHeader chunk_h;
ULONG skip_bytes;
BOOLEAN vhdr_found = FALSE;
BOOLEAN body_found = FALSE;
InputFormat.bits = 8; /* True of all 8SVX */
InputFormat.zero = 0; /* Ditto */
while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
{
offset += sizeof chunk_h;
switch (chunk_h.ckID)
{
case ID_VHDR:
vhdr_found = TRUE;
error = read_vhdr (form_cksize, chunk_h);
offset += WordAlign (chunk_h.ckSize);
break;
case ID_BODY:
body_found = TRUE;
FileDataOffset = offset;
if (!vhdr_found && !error) /* If still looking for VHDR */
{
skip_bytes = WordAlign (chunk_h.ckSize);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
break;
default:
skip_bytes = WordAlign (chunk_h.ckSize);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
break;
}
if (error || (vhdr_found && body_found))
{
break;
}
}
if (!vhdr_found || !body_found || error)
{
if (error <= CORRUPT) /* Higher errors reported elsewhere */
{
error_message (CORRUPT_IFF);
}
}
else
{
FileFormatOK = TRUE;
}
}
static int read_vhdr (ULONG form_cksize, struct ChunkHeader chunk_h)
{
int error = CORRUPT; /* defaulted if chunk not completely read */
struct VHDR vhdr;
ULONG skip_bytes;
if (chunk_h.ckSize < sizeof vhdr)
{
return CORRUPT; /* Error! Pre '85 or corrupt! */
}
if (fread (&vhdr, sizeof vhdr, 1, ReadPtr))
{
FileRate = vhdr.samplesPerSec;
if (vhdr.sCompression)
{
error_message (COMPRESSION_NOT_SUPPORTED);
return UNAVAIL_COMPRESSION;
}
FileVolume = vhdr.volume / 65536.0L;
FileOctaves = vhdr.ctOctave;
FileOneShotHiFrames = vhdr.oneShotHiSamples;
FileRepeatHiFrames = vhdr.repeatHiSamples;
FileFrames = FileOneShotHiFrames + FileRepeatHiFrames;
error = NO_ERROR;
if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof vhdr)) /* = */
{
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
}
return error;
}
static void read_aiff_format (long form_cksize)
/*
* Chunks are allowed to be in any order.
* But, a fast and lazy approach is taken to validation:
* Chunks looked for: Common (COMM) and Sound Data (SSND)
* (Note: COMM here is different from the AIFC version.)
* (Once those two have been found, and COMM read, I exit.)
* SSND chunk isn't read (so premature file end must be detected later)
* SSND chunk is fseek'd over only if VHDR hasn't been found yet.
* form_cksize isn't actually checked
*/
{
ULONG skip_bytes;
int error = NO_ERROR;
struct ChunkHeader chunk_h;
struct SoundDataChunkInfo sdci;
BOOLEAN ssnd_found = FALSE;
BOOLEAN comm_found = FALSE;
while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
{
offset += sizeof chunk_h;
switch (chunk_h.ckID)
{
case ID_COMM:
comm_found = TRUE;
error = read_comm_aiff (form_cksize, chunk_h);
offset += WordAlign (chunk_h.ckSize);
break;
case ID_SSND:
ssnd_found = TRUE;
error = !fread (&sdci, sizeof sdci, 1, ReadPtr);
offset += sizeof sdci;
FileDataOffset = offset + sdci.offset;
if (!comm_found && !error)
{
skip_bytes = WordAlign (chunk_h.ckSize - sizeof sdci);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
break;
default:
skip_bytes = WordAlign (chunk_h.ckSize);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
break;
}
if (error || (comm_found && ssnd_found))
{
break;
}
}
if (!comm_found || !ssnd_found || error)
{
if (error <= CORRUPT) /* Higher errors reported elsewhere */
{
error_message (CORRUPT_AIFF);
}
}
else
{
FileFormatOK = TRUE;
}
}
static int read_comm_aiff (ULONG form_cksize, struct ChunkHeader chunk_h)
{
int error = CORRUPT; /* defaulted if chunk not completely read */
int skip_bytes;
struct CommAiff comm;
if (chunk_h.ckSize < sizeof comm)
{
return CORRUPT; /* Error...corrupt or unsupported AIFF format */
}
if (fread (&comm, sizeof comm, 1, ReadPtr))
{
FileChannels = comm.numChannels;
FileFrames = comm.numSampleFrames;
InputFormat.bits = comm.sampleSize;
InputFormat.zero = 0;
FileRate = double_from_extended (comm.sampleRate);
error = NO_ERROR;
if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof comm)) /* = */
{
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
}
return error;
}
static void read_aifc_format (long form_cksize)
/*
* Chunks are allowed to be in any order.
* But, a fast and lazy approach is taken to validation:
* Chunks looked for: COMM and SSND
* (Once those two have been found, and COMM read, I exit.)
* SSND chunk isn't read (so premature file end must be detected later)
* SSND chunk is fseek'd over only if VHDR hasn't been found yet.
* form_cksize isn't actually checked
*/
{
ULONG skip_bytes;
int error = NO_ERROR;
struct ChunkHeader chunk_h;
struct SoundDataChunkInfo sdci;
BOOLEAN ssnd_found = FALSE;
BOOLEAN comm_found = FALSE;
while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
{
offset += sizeof chunk_h;
switch (chunk_h.ckID)
{
case ID_COMM:
comm_found = TRUE;
error = read_comm_aifc (form_cksize, chunk_h);
offset += WordAlign (chunk_h.ckSize);
break;
case ID_SSND:
ssnd_found = TRUE;
error = !fread (&sdci, sizeof sdci, 1, ReadPtr);
offset += sizeof sdci;
FileDataOffset = offset + sdci.offset;
if (!comm_found && !error)
{
skip_bytes = WordAlign (chunk_h.ckSize - sizeof sdci);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
break;
default:
skip_bytes = WordAlign (chunk_h.ckSize);
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
break;
}
if (error || (comm_found && ssnd_found))
{
break;
}
}
if (!comm_found || !ssnd_found || error)
{
if (error <= CORRUPT)
{
error_message (CORRUPT_AIFC);
}
}
else
{
FileFormatOK = TRUE;
}
}
static int read_comm_aifc (ULONG form_cksize, struct ChunkHeader chunk_h)
{
int error = CORRUPT; /* Defaulted if chunk not read */
int skip_bytes;
struct CommAifc comm;
if (chunk_h.ckSize < sizeof comm)
{
return CORRUPT; /* Error...corrupt or unsupported AIFF format */
}
if (fread (&comm, sizeof comm, 1, ReadPtr))
{
FileChannels = comm.numChannels;
FileFrames = comm.numSampleFrames;
InputFormat.bits = comm.sampleSize;
InputFormat.zero = 0;
FileRate = double_from_extended (comm.sampleRate);
if (comm.compressionType != ID_NONE)
{
error_message (COMPRESSION_NOT_SUPPORTED);
return UNAVAIL_COMPRESSION;
}
error = NO_ERROR;
if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof comm)) /* = */
{
error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
offset += skip_bytes;
}
}
return error;
}
/*
* The following is based on ideas from ConvertFromIeeeExtended
* by Malcolm Slaney and Ken Turkowski. However, since that was
* copyright by Apple Computer, Inc., I have prepared an original
* implementation here.
*
* Note: NaN's and infinities are converted to HUGE_VAL. This is
* not very nice for NaN's.
*
* WARNING! THIS HASN'T BEEN WELL TESTED, SO I WOULDN'T USE THIS FOR
* OTHER OR SERIOUS PURPOSES OR ON OTHER ARCHITECTURES.
*/
#define UPPER_EXP_MASK 0x7F
#define SIGN_MASK 0x80
#define INFINITE_EXPONENT 0x7FFF
#define HI_E_OFF 16414 /* (16383 + 31) */
#define LO_E_OFF 16446 /* (16383 + 31 + 32) */
#define U_TO_F(u) (((double) ((long) ((u)-2147483647L-1))) + 2147483648.0)
static double double_from_extended (UBYTE *extended)
{
double dval;
ULONG high_mantissa;
ULONG low_mantissa;
int exponent;
exponent = ((extended[0] & UPPER_EXP_MASK) << 8) | extended[1];
high_mantissa = ((ULONG) (extended[2] << 24)) |
((ULONG) (extended[3] << 16)) |
((ULONG) (extended[4] << 8)) |
(ULONG) extended[5];
low_mantissa = ((ULONG) (extended[6] << 24)) |
((ULONG) (extended[7] << 16)) |
((ULONG) (extended[8] << 8)) |
(ULONG) extended[9];
if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0)
{
dval = 0;
}
else
{
if (exponent == INFINITE_EXPONENT) /* Infinity or NaN */
{
dval = HUGE_VAL; /* from ANSI C math.h */
}
else
{
dval = ldexp ( U_TO_F (high_mantissa), exponent - HI_E_OFF) +
ldexp ( U_TO_F (low_mantissa), exponent - LO_E_OFF);
}
if (extended[0] & SIGN_MASK)
{
dval = (-dval);
}
}
return dval;
}
static void read_avr_format (void)
{
struct AVRH avrh;
if (!fread (&avrh, sizeof avrh, 1, ReadPtr))
{
error_message (CORRUPT_AVR);
}
else
{
FileFormatOK = TRUE;
FileDataOffset = sizeof (ID) + sizeof (struct AVRH);
if (avrh.mono == 0)
{
FileChannels = 1;
}
else if (avrh.mono == -1)
{
FileChannels = 2;
}
else
{
error_message (CORRUPT_AVR);
FileFormatOK = FALSE;
}
InputFormat.bits = avrh.rez;
if (InputFormat.bits > 16 || InputFormat.bits < 0)
{
error_message (CORRUPT_AVR);
FileFormatOK = FALSE;
}
if (avrh.sign == -1)
{
InputFormat.zero = 0;
}
else if (avrh.sign == 0)
{
int sample_width = (InputFormat.bits > 8) ? 16 : 8;
InputFormat.zero = ((unsigned long) 0xffffffff >>
(33 - sample_width)) + (unsigned long) 1;
}
else
{
error_message (CORRUPT_AVR);
FileFormatOK = FALSE;
}
FileRate = avrh.rate & 0xFFFFFF; /* I don't understand why */
/*
* Maybe FF in upper bits MEANS number is an integer, no FF means float
* But, my docs didn't say this
*/
FileFrames = avrh.size;
if (FileFrames < 0)
{
error_message (CORRUPT_AVR);
FileFormatOK = FALSE;
}
if (avrh.res2)
{
error_message (COMPRESSION_NOT_SUPPORTED);
FileFormatOK = FALSE;
}
}
}